/* !
 * (c) Copyright 2025 Palantir Technologies Inc. All rights reserved.
 */

/**
 * Prop-type definitions for the <Box> component.
 *
 * The guiding idea behind <Box> is to provide a small, typed subset of the
 * CSS box-model and flexbox APIs as *props* instead of requiring consumers to
 * write custom styles or class names. We purposefully whitelist only a finite
 * number of safe values (see the union literals below) so that:
 *
 * 1. Design-system-approved spacing / sizing tokens can be enforced at compile
 *    time.
 * 2. We can consistently translate prop values into utility class names
 *    generated by `buildStyles`.
 * 3. Invalid HTML attributes (e.g. `foo="bar"`) are rejected by TypeScript in
 *    user code, while *supported* DOM props such as `id`, `title`, etc. are
 *    still allowed through the generic overlay.
 */

import type * as React from "react";

/**
 * The range of values for spacing tokens.
 */
type SpacingRange = 0 | 0.5 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;

/**
 * The range of values for size as a percentage.
 */
type SizeRange = 25 | 50 | 75 | 100;

/**
 * The range of values for `gap`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/gap
 */
export type Gap = SpacingRange | `${SpacingRange}`;

/**
 * The range of values for `margin`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/margin
 */
export type Margin = SpacingRange | `${SpacingRange}` | "auto";

/**
 * The range of values for `padding`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/padding
 */
export type Padding = SpacingRange | `${SpacingRange}`;

/**
 * The range of values for `inset`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/inset
 */
export type Inset = SpacingRange | `${SpacingRange}`;

/**
 * The range of values for `width`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/width
 */
export type Width = SizeRange | `${SizeRange}` | "auto";

/**
 * The range of values for `height`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/height
 */
export type Height = SizeRange | `${SizeRange}` | "auto";

/**
 * The range of values for `align-content`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/align-content
 */
export type AlignContent =
    | "start"
    | "center"
    | "end"
    | "space-between"
    | "space-around"
    | "space-evenly"
    | "stretch"
    | "normal"
    | "baseline";

/**
 * The range of values for `align-items`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/align-items
 */
export type AlignItems = "start" | "end" | "center" | "baseline" | "stretch";

/**
 * The range of values for `align-self`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/align-self
 */
export type AlignSelf = "auto" | "start" | "end" | "center" | "baseline" | "stretch";

/**
 * The range of values for `display`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/display
 */
export type Display =
    | "block"
    | "inline-block"
    | "inline"
    | "flex"
    | "inline-flex"
    | "grid"
    | "inline-grid"
    | "table"
    | "inline-table"
    | "table-cell"
    | "table-row"
    | "none";

/**
 * The range of values for `flex`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/flex
 */
export type Flex = 1 | "1" | "auto" | "initial" | "none";

/**
 * The range of values for `flex-direction`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction
 */
export type FlexDirection = "row" | "row-reverse" | "column" | "column-reverse";

/**
 * The range of values for `flex-wrap`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/flex-wrap
 */
export type FlexWrap = "nowrap" | "wrap" | "wrap-reverse";

/**
 * The range of values for `justify-content`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content
 */
export type JustifyContent =
    | "start"
    | "center"
    | "end"
    | "space-between"
    | "space-around"
    | "space-evenly"
    | "stretch"
    | "normal";

/**
 * The range of values for `justify-items`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/justify-items
 */
export type JustifyItems = "start" | "end" | "center" | "stretch";

/**
 * The range of values for `justify-self`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/justify-self
 */
export type JustifySelf = "auto" | "start" | "end" | "center" | "stretch";

/**
 * The range of values for `overflow`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/overflow
 */
export type Overflow = "visible" | "hidden" | "scroll" | "auto";

/**
 * The range of values for `position`.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/CSS/position
 */
export type Position = "static" | "absolute" | "relative" | "fixed" | "sticky";

/**
 * Props for the `<Box>` component.
 *
 * Extends standard HTML div props with Box-specific layout props.
 */
export interface BoxProps extends React.ComponentPropsWithoutRef<"div"> {
    /**
     * When true, `<Box>` will **not** render an extra wrapper element. Instead, it will
     * clone & enhance its single child element, merging class names and props.
     */
    asChild?: boolean;

    /** Shorthand for the CSS `gap` property (applies to flex and grid layouts). */
    gap?: Gap;

    // ────────────────────────────────────────────────────────────
    // Margin
    // ────────────────────────────────────────────────────────────

    /** CSS `margin` */
    margin?: Margin;
    /** CSS `margin-inline` */
    marginX?: Margin;
    /** CSS `margin-inline-start` */
    marginXStart?: Margin;
    /** CSS `margin-inline-end` */
    marginXEnd?: Margin;
    /** CSS `margin-block` */
    marginY?: Margin;
    /** CSS `margin-block-start` */
    marginYStart?: Margin;
    /** CSS `margin-block-end` */
    marginYEnd?: Margin;
    /** CSS `margin-top` */
    marginTop?: Margin;
    /** CSS `margin-right` */
    marginRight?: Margin;
    /** CSS `margin-bottom` */
    marginBottom?: Margin;
    /** CSS `margin-left` */
    marginLeft?: Margin;

    // ────────────────────────────────────────────────────────────
    // Padding
    // ────────────────────────────────────────────────────────────

    /** CSS `padding` */
    padding?: Padding;
    /** CSS `padding-inline` */
    paddingX?: Padding;
    /** CSS `padding-inline-start` */
    paddingXStart?: Padding;
    /** CSS `padding-inline-end` */
    paddingXEnd?: Padding;
    /** CSS `padding-block` */
    paddingY?: Padding;
    /** CSS `padding-block-start` */
    paddingYStart?: Padding;
    /** CSS `padding-block-end` */
    paddingYEnd?: Padding;
    /** CSS `padding-top` */
    paddingTop?: Padding;
    /** CSS `padding-right` */
    paddingRight?: Padding;
    /** CSS `padding-bottom` */
    paddingBottom?: Padding;
    /** CSS `padding-left` */
    paddingLeft?: Padding;

    // ────────────────────────────────────────────────────────────
    // Inset
    // ────────────────────────────────────────────────────────────

    /** CSS `inset` */
    inset?: Inset;
    /** CSS `inset-inline` */
    insetX?: Inset;
    /** CSS `inset-inline-start` */
    insetXStart?: Inset;
    /** CSS `inset-inline-end` */
    insetXEnd?: Inset;
    /** CSS `inset-block` */
    insetY?: Inset;
    /** CSS `inset-block-start` */
    insetYStart?: Inset;
    /** CSS `inset-block-end` */
    insetYEnd?: Inset;
    /** CSS `top` */
    insetTop?: Inset;
    /** CSS `right` */
    insetRight?: Inset;
    /** CSS `bottom` */
    insetBottom?: Inset;
    /** CSS `left` */
    insetLeft?: Inset;

    // ────────────────────────────────────────────────────────────
    // Size
    // ────────────────────────────────────────────────────────────

    /** CSS `width` */
    width?: Width;
    /** CSS `height` */
    height?: Height;

    // ────────────────────────────────────────────────────────────
    // Flexbox & Grid alignment
    // ────────────────────────────────────────────────────────────

    /** CSS `align-content` */
    alignContent?: AlignContent;
    /** CSS `align-items` */
    alignItems?: AlignItems;
    /** CSS `align-self` */
    alignSelf?: AlignSelf;

    /** CSS `display` */
    display?: Display;
    /** CSS `flex` (shorthand for `flex-grow`, `flex-shrink`, `flex-basis`) */
    flex?: Flex;
    /** CSS `flex-direction` */
    flexDirection?: FlexDirection;
    /** CSS `flex-wrap` */
    flexWrap?: FlexWrap;

    /** CSS `justify-content` */
    justifyContent?: JustifyContent;
    /** CSS `justify-items` */
    justifyItems?: JustifyItems;
    /** CSS `justify-self` */
    justifySelf?: JustifySelf;

    // ────────────────────────────────────────────────────────────
    // Position & Overflow
    // ────────────────────────────────────────────────────────────

    /** CSS `position` */
    position?: Position;

    /** CSS `overflow` */
    overflow?: Overflow;
    /** CSS `overflow-x` */
    overflowX?: Overflow;
    /** CSS `overflow-y` */
    overflowY?: Overflow;
}
